#ifndef LEAKY_RELU_BP_NETWORK_HPP
#define LEAKY_RELU_BP_NETWORK_HPP

#include "LeakyReLU.hpp"
#include "Network.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
#include <cmath>

class LeakyReLUBPNetwork : public Network {
private:
	std::vector<std::vector<LeakyNeuron>> layers;
	double learning_rate;
	
public:
	LeakyReLUBPNetwork(const std::vector<size_t>& layerSizes, double lr = 0.01) 
	: learning_rate(lr) {
		if (layerSizes.size() < 2) {
			throw std::invalid_argument("LeakyReLUBPNetwork: 网络至少需包含输入层和输出层");
		}
		for (size_t i = 1; i < layerSizes.size(); ++i) {
			size_t inputDim = layerSizes[i-1];
			std::vector<LeakyNeuron> currentLayer;
			for (size_t j = 0; j < layerSizes[i]; ++j) {
				currentLayer.emplace_back(inputDim);
			}
			layers.push_back(currentLayer);
		}
	}
	
	std::vector<double> get(const std::vector<double>& input) override {
		if (input.size() != layers[0][0].weights.size()) {
			throw std::invalid_argument("LeakyReLUBPNetwork: 输入维度与网络不匹配");
		}
		std::vector<double> currentInput = input;
		for (auto& layer : layers) {
			std::vector<double> currentOutput;
			for (auto& neuron : layer) {
				currentOutput.push_back(neuron.count(currentInput));
			}
			currentInput = currentOutput;
		}
		return currentInput;
	}
	
	void train(const std::vector<double>& input, const std::vector<double>& expected) override {
		std::vector<double> output = get(input);
		if (output.size() != expected.size()) {
			throw std::invalid_argument("LeakyReLUBPNetwork: 期望输出维度与网络输出不匹配");
		}
		
		std::vector<std::vector<double>> deltas;
		std::vector<double> outputDeltas;
		const auto& outputLayer = layers.back();
		for (size_t i = 0; i < output.size(); ++i) {
			double error = expected[i] - output[i];
			double deriv = outputLayer[i].getActDeriv();
			outputDeltas.push_back(error * deriv);
		}
		deltas.push_back(outputDeltas);
		
		for (int i = layers.size() - 2; i >= 0; --i) {
			const auto& currentLayer = layers[i];
			const auto& nextLayer = layers[i+1];
			const auto& nextDeltas = deltas[0];
			std::vector<double> currentDeltas;
			
			for (size_t j = 0; j < currentLayer.size(); ++j) {
				double error = 0.0;
				for (size_t k = 0; k < nextLayer.size(); ++k) {
					error += nextDeltas[k] * nextLayer[k].weights[j];
				}
				double deriv = currentLayer[j].getActDeriv();
				currentDeltas.push_back(error * deriv);
			}
			deltas.insert(deltas.begin(), currentDeltas);
		}
		
		std::vector<double> prevOutput = input;
		for (size_t i = 0; i < layers.size(); ++i) {
			auto& layer = layers[i];
			const auto& currentDeltas = deltas[i];
			std::vector<double> currentOutput;
			
			for (size_t j = 0; j < layer.size(); ++j) {
				auto& neuron = layer[j];
				double delta = currentDeltas[j];
				
				neuron.bias += learning_rate * delta;
				for (size_t k = 0; k < neuron.weights.size(); ++k) {
					neuron.weights[k] += learning_rate * delta * prevOutput[k];
				}
				
				currentOutput.push_back(neuron.post_act);
			}
			prevOutput = currentOutput;
		}
	}
	
	// 修复的store函数：先将斜率存入临时变量（左值）再取地址
	void store(const std::string& filename) const override {
		std::ofstream file(filename, std::ios::binary);
		if (!file.is_open()) {
			throw std::runtime_error("LeakyReLUBPNetwork: 无法打开文件保存模型");
		}
		
		// 保存学习率
		file.write(reinterpret_cast<const char*>(&learning_rate), sizeof(learning_rate));
		// 保存层数
		size_t numLayers = layers.size();
		file.write(reinterpret_cast<const char*>(&numLayers), sizeof(numLayers));
		
		// 保存每层信息
		for (const auto& layer : layers) {
			// 保存当前层神经元数量
			size_t numNeurons = layer.size();
			file.write(reinterpret_cast<const char*>(&numNeurons), sizeof(numNeurons));
			
			// 保存每个LeakyNeuron的参数
			for (const auto& neuron : layer) {
				// 保存权重数量
				size_t numWeights = neuron.weights.size();
				file.write(reinterpret_cast<const char*>(&numWeights), sizeof(numWeights));
				// 保存权重
				for (double w : neuron.weights) {
					file.write(reinterpret_cast<const char*>(&w), sizeof(w));
				}
				// 保存偏置
				file.write(reinterpret_cast<const char*>(&neuron.bias), sizeof(neuron.bias));
				// 关键修复：先将斜率存入临时变量（左值），避免右值取地址错误
				double neuronSlope = neuron.getSlope();  // 临时变量（左值）
				file.write(reinterpret_cast<const char*>(&neuronSlope), sizeof(neuronSlope));
			}
		}
	}
	
	void load(const std::string& filename) override {
		std::ifstream file(filename, std::ios::binary);
		if (!file.is_open()) {
			throw std::runtime_error("LeakyReLUBPNetwork: 无法打开文件加载模型");
		}
		
		layers.clear();
		
		// 加载学习率
		file.read(reinterpret_cast<char*>(&learning_rate), sizeof(learning_rate));
		// 加载层数
		size_t numLayers;
		file.read(reinterpret_cast<char*>(&numLayers), sizeof(numLayers));
		
		// 加载每层信息
		for (size_t i = 0; i < numLayers; ++i) {
			// 加载当前层神经元数量
			size_t numNeurons;
			file.read(reinterpret_cast<char*>(&numNeurons), sizeof(numNeurons));
			
			std::vector<LeakyNeuron> currentLayer;
			for (size_t j = 0; j < numNeurons; ++j) {
				// 加载权重数量
				size_t numWeights;
				file.read(reinterpret_cast<char*>(&numWeights), sizeof(numWeights));
				// 加载权重
				std::vector<double> weights(numWeights);
				for (size_t k = 0; k < numWeights; ++k) {
					file.read(reinterpret_cast<char*>(&weights[k]), sizeof(weights[k]));
				}
				// 加载偏置
				double bias;
				file.read(reinterpret_cast<char*>(&bias), sizeof(bias));
				// 加载负斜率
				double slope;
				file.read(reinterpret_cast<char*>(&slope), sizeof(slope));
				
				// 构造LeakyNeuron
				LeakyNeuron neuron(numWeights, slope);
				neuron.weights = weights;
				neuron.bias = bias;
				currentLayer.push_back(neuron);
			}
			layers.push_back(currentLayer);
		}
	}
	
	void setLearningRate(double lr) {
		if (lr <= 0) {
			throw std::invalid_argument("LeakyReLUBPNetwork: 学习率必须为正数");
		}
		learning_rate = lr;
	}
	
	double getLearningRate() const {
		return learning_rate;
	}
	
	void setNeuronSlope(size_t layerIdx, size_t neuronIdx, double newSlope) {
		if (layerIdx >= layers.size()) {
			throw std::out_of_range("LeakyReLUBPNetwork: 层索引超出范围");
		}
		if (neuronIdx >= layers[layerIdx].size()) {
			throw std::out_of_range("LeakyReLUBPNetwork: 神经元索引超出范围");
		}
		layers[layerIdx][neuronIdx].setSlope(newSlope);
	}
	
	virtual ~LeakyReLUBPNetwork() = default;
};

#endif  // LEAKY_RELU_BP_NETWORK_HPP